#include "EventLogonPage.h"

#include "EventNetwork.h"

#include <libintl.h>
#define _(String)  gettext(String)
#define N_(String) String

/* EventLogonPage 对象的信号 */
static guint logon_signal;

struct _EventLogonPage
{
	AdwBin parent_instance;
	//
	AdwEntryRow	    *phone_entry;
	AdwPasswordEntryRow *password_entry;
	AdwEntryRow	    *address_entry;
	AdwEntryRow	    *vcode_entry;
	AdwEntryRow	    *user_name_entry;
	GtkLabel	    *entry_error_info;
	GtkLabel	    *title_label;
	GtkButton	    *logon_button;

	/* 关联的返回按钮 */
	GtkButton *relate_return_button;

	/* 是否处于注册状态 */
	bool is_registering;

	/* 是否需要验证码登陆 */
	bool is_need_verification_code;

	/* 是否第一次来到注册界面 */
	bool is_first_goto_register_page;
};

G_DEFINE_FINAL_TYPE(EventLogonPage, event_logon_page, ADW_TYPE_BIN)

static void
unset_entry_error_state_color_cb(AdwEntryRow *self, EventLogonPage *page)
{
	gint		   status;
	static const char *css = "entry-input-error";
	//
	status = GPOINTER_TO_INT(
		g_object_get_data(G_OBJECT(self), "is-error-entry"));
	if (!status)
		return;
	gtk_widget_remove_css_class(GTK_WIDGET(self), css);
	g_object_set_data(G_OBJECT(self), "is-error-entry", GINT_TO_POINTER(0));
}

/* 检测电话号码是否正确，不正确为 true */
static bool
detect_input_is_number(const char *phone, int bytes)
{
	for (int i = 0; i < bytes; ++i)
		if (phone[i] < '0' || phone[i] > '9')
			return true;
	return false;
}

/**
 * @brief 检查输入框的内容是否为空，或者长度是否正确。
 *        同时将会把正确的输入保存到 EventNetwork 中
 * @return 不正确为 true，正确为 false
 */
static bool
detect_input_content(EventLogonPage *self)
{
	static const char *css[] = { "entry-input-error", NULL };
	const char	  *phone = NULL, *password = NULL, *address = NULL,
		   *vcode = NULL, *uname = NULL;

	address = gtk_editable_get_text(GTK_EDITABLE(self->address_entry));
	if (event_network_check_address(address, NULL) != 1) {
		gtk_label_set_label(self->entry_error_info,
				    _("Please enter the server address with "
				      "correct format."));
		g_object_set_data(G_OBJECT(self->address_entry),
				  "is-error-entry", GINT_TO_POINTER(1));
		goto high_light_entry;
	} else {
		address = NULL;
	}

	uname = gtk_editable_get_text(GTK_EDITABLE(self->user_name_entry));
	if (self->is_registering && strlen(uname) == 0) {
		gtk_label_set_label(self->entry_error_info,
				    _("Please enter the user name."));
		g_object_set_data(G_OBJECT(self->user_name_entry),
				  "is-error-entry", GINT_TO_POINTER(1));
		goto high_light_entry;
	} else {
		uname = NULL;
	}

	phone = gtk_editable_get_text(GTK_EDITABLE(self->phone_entry));
	if (detect_input_is_number(phone, 11)) {
		gtk_label_set_label(
			self->entry_error_info,
			_("Please enter the correct phone number."));
		g_object_set_data(G_OBJECT(self->phone_entry), "is-error-entry",
				  GINT_TO_POINTER(1));
		goto high_light_entry;
	} else {
		phone = NULL;
	}

	password = gtk_editable_get_text(GTK_EDITABLE(self->password_entry));
	if (strlen(password) == 0) {
		gtk_label_set_label(self->entry_error_info,
				    _("Please enter the password."));
		g_object_set_data(G_OBJECT(self->password_entry),
				  "is-error-entry", GINT_TO_POINTER(1));
		phone = NULL;
		goto high_light_entry;
	} else {
		password = NULL;
	}

	if (self->is_registering || !self->is_need_verification_code)
		return false;

	vcode = gtk_editable_get_text(GTK_EDITABLE(self->vcode_entry));
	if (detect_input_is_number(vcode, 4)) {
		gtk_label_set_label(
			self->entry_error_info,
			_("Please enter a valid verification code."));
		g_object_set_data(G_OBJECT(self->vcode_entry), "is-error-entry",
				  GINT_TO_POINTER(1));
		goto high_light_entry;
	}

	return false;

high_light_entry:
	if (phone)
		gtk_widget_set_css_classes(GTK_WIDGET(self->phone_entry), css);
	if (password) {
		gtk_widget_set_css_classes(GTK_WIDGET(self->password_entry),
					   css);
	}
	if (address)
		gtk_widget_set_css_classes(GTK_WIDGET(self->address_entry),
					   css);
	if (vcode)
		gtk_widget_set_css_classes(GTK_WIDGET(self->vcode_entry), css);
	if (uname && self->is_registering) {
		gtk_widget_set_css_classes(GTK_WIDGET(self->user_name_entry),
					   css);
	}
	return true;
}

static void
login_submit_cb(EventLogonPage *self, gpointer data)
{
	if (detect_input_content(self))
		return;

	const char  *address, *phone_str, *password, *vcode;
	ResponseType re_type;
	bool	     is_need_verification_code;

	address			  = event_logon_page_get_address(self);
	phone_str		  = event_logon_page_get_phone_str(self);
	password		  = event_logon_page_get_password(self);
	vcode			  = event_logon_page_get_vcode(self);
	is_need_verification_code = event_logon_page_is_need_verification(self);

	event_network_set_server_address(event_network, address);
	event_network_set_phone_password(event_network, phone_str, password);
	if (is_need_verification_code)
		event_network_set_verification_code(event_network, vcode);
	else
		event_network_set_verification_code(event_network, NULL);
	re_type = event_network_try_logon(event_network);
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		event_logon_page_show_error_info(
			self, event_network_get_error_info(event_network));
		break;
	case RESPONSE_TYPE_SUCCESS:
	case RESPONSE_TYPE_RETURN_VERIFY_CODE:
		g_signal_emit(self, logon_signal, 0);
		break;
	case RESPONSE_TYPE_NEED_VERIFICATION_CODE:
		event_network_clean_online_id(event_network);
		gtk_widget_set_visible(GTK_WIDGET(self->relate_return_button),
				       false);
		event_logon_page_set_page_type(self,
					       EVENT_LOGON_PAGE_TYPE_LOGON);
		event_logon_page_need_verification_code_entry(self);
		event_logon_page_show_error_info(self,
						 _(response_type[re_type]));
		break;
	default:
		event_logon_page_show_error_info(self,
						 _(response_type[re_type]));
		break;
	}
}

static void
go_to_logon_page_cb(EventLogonPage *self, gpointer data)
{
	event_logon_page_set_page_type(self, EVENT_LOGON_PAGE_TYPE_LOGON);
}

static void
register_function_cb(EventLogonPage *self, gpointer data)
{
	const char  *address, *phone_str, *user_name, *password;
	ResponseType re_type;

	gtk_widget_set_visible(GTK_WIDGET(self->logon_button), false);
	event_logon_page_set_page_type(self, EVENT_LOGON_PAGE_TYPE_REGISTER);
	if (self->is_first_goto_register_page) {
		self->is_first_goto_register_page = false;
		return;
	}
	if (detect_input_content(self))
		return;

	address	  = event_logon_page_get_address(self);
	phone_str = event_logon_page_get_phone_str(self);
	user_name = event_logon_page_get_user_name(self);
	password  = event_logon_page_get_password(self);

	event_network_set_server_address(event_network, address);
	event_network_set_user_name(event_network, user_name);
	event_network_set_phone_password(event_network, phone_str, password);

	re_type = event_network_try_register(event_network);
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		event_logon_page_show_error_info(
			self, event_network_get_error_info(event_network));
		break;
	case RESPONSE_TYPE_SUCCESS:
		event_logon_page_set_page_type(self,
					       EVENT_LOGON_PAGE_TYPE_LOGON);
		event_logon_page_show_error_info(self,
						 _("Registered successfully."));
		break;
	default:
		event_logon_page_show_error_info(self,
						 _(response_type[re_type]));
		break;
	}
}

EventLogonPageType
event_logon_get_page_type(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, EVENT_LOGON_PAGE_TYPE_LOGON);
	return self->is_registering ? EVENT_LOGON_PAGE_TYPE_REGISTER :
				      EVENT_LOGON_PAGE_TYPE_LOGON;
}

void
event_logon_page_set_page_type(EventLogonPage	 *self,
			       EventLogonPageType page_type)
{
	g_return_if_fail(self != NULL);

	switch (page_type) {
	case EVENT_LOGON_PAGE_TYPE_LOGON:
		self->is_registering = false;
		gtk_widget_set_visible(GTK_WIDGET(self->user_name_entry),
				       false);
		gtk_widget_set_visible(GTK_WIDGET(self->logon_button), true);
		gtk_label_set_label(self->title_label, _("Logon"));
		if (self->is_need_verification_code)
			gtk_widget_set_visible(GTK_WIDGET(self->vcode_entry),
					       true);
		self->is_first_goto_register_page = true;
		return;
	case EVENT_LOGON_PAGE_TYPE_REGISTER:
		self->is_registering = true;
		gtk_widget_set_visible(GTK_WIDGET(self->user_name_entry), true);
		gtk_widget_set_visible(GTK_WIDGET(self->vcode_entry), false);
		gtk_label_set_label(self->title_label, _("Register"));
		if (self->is_first_goto_register_page) {
			gtk_widget_set_visible(
				GTK_WIDGET(self->relate_return_button), true);
		}
		return;
	}
}

void
event_logon_page_show_error_info(EventLogonPage *self, const char *error_info)
{
	g_return_if_fail(self != NULL);
	if (error_info)
		gtk_label_set_label(self->entry_error_info, error_info);
	else
		gtk_label_set_label(self->entry_error_info, "");
}

void
event_logon_page_set_default_content(EventLogonPage *self, const char *address,
				     const char *phone_str,
				     const char *password)
{
	g_return_if_fail(self != NULL);

	if (address) {
		gtk_editable_set_text(GTK_EDITABLE(self->address_entry),
				      address);
	}
	if (phone_str) {
		gtk_editable_set_text(GTK_EDITABLE(self->phone_entry),
				      phone_str);
	}
	if (password) {
		gtk_editable_set_text(GTK_EDITABLE(self->password_entry),
				      password);
	}
}

void
event_logon_page_need_verification_code_entry(EventLogonPage *self)
{
	g_return_if_fail(self != NULL);
	self->is_need_verification_code = true;
	gtk_widget_set_visible(GTK_WIDGET(self->vcode_entry), true);
}

const char *
event_logon_page_get_address(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_editable_get_text(GTK_EDITABLE(self->address_entry));
}

const char *
event_logon_page_get_phone_str(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_editable_get_text(GTK_EDITABLE(self->phone_entry));
}

const char *
event_logon_page_get_password(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_editable_get_text(GTK_EDITABLE(self->password_entry));
}

const char *
event_logon_page_get_vcode(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_editable_get_text(GTK_EDITABLE(self->vcode_entry));
}

const char *
event_logon_page_get_user_name(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_editable_get_text(GTK_EDITABLE(self->user_name_entry));
}

bool
event_logon_page_is_need_verification(EventLogonPage *self)
{
	g_return_val_if_fail(self != NULL, false);
	return self->is_need_verification_code;
}

static void
phone_entry_delete_cb(EventLogonPage *self, gpointer data)
{
	static int start_app = 1;
	if (start_app)
		start_app = 0;
	else
		event_network_clean_online_id(event_network);
}

void
event_logon_page_clean_up_vcode(EventLogonPage *self)
{
	g_return_if_fail(self != NULL);
	gtk_editable_set_text(GTK_EDITABLE(self->vcode_entry), "");
}

void
event_logon_page_set_relate_return_button(EventLogonPage *self,
					  GtkButton	 *relate_button)
{
	g_return_if_fail(self != NULL && relate_button != NULL);
	self->relate_return_button = relate_button;
}

void
event_logon_page_try_auto_logon(EventLogonPage *self)
{
	if (event_network_have_local_property(event_network)) {
		event_logon_page_set_default_content(
			self, event_network_get_address(event_network),
			event_network_get_phone(event_network),
			event_network_get_password(event_network));
		login_submit_cb(self, NULL);
	}
}

static void
event_logon_page_finalize(GObject *object)
{
	G_OBJECT_CLASS(event_logon_page_parent_class)->finalize(object);
}

static void
event_logon_page_class_init(EventLogonPageClass *klass)
{
	GObjectClass   *object_class = G_OBJECT_CLASS(klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	gtk_widget_class_set_template_from_resource(
		widget_class, "/org/korack/event/ui/EventLogonPage.ui");
	gtk_widget_class_bind_template_callback(
		widget_class, unset_entry_error_state_color_cb);

	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     phone_entry);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     password_entry);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     address_entry);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     vcode_entry);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     user_name_entry);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     entry_error_info);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     title_label);
	gtk_widget_class_bind_template_child(widget_class, EventLogonPage,
					     logon_button);

	gtk_widget_class_bind_template_callback(widget_class, login_submit_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						register_function_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						go_to_logon_page_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						phone_entry_delete_cb);

	logon_signal = g_signal_newv(
		"logon", G_TYPE_FROM_CLASS(object_class),
		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		NULL, NULL, NULL, NULL, G_TYPE_NONE, 0, NULL);
	//
	object_class->finalize = event_logon_page_finalize;
}

static void
event_logon_page_init(EventLogonPage *self)
{
	gtk_widget_init_template(GTK_WIDGET(self));

	g_object_set_data(G_OBJECT(self->phone_entry), "is-error-entry",
			  GINT_TO_POINTER(0));
	g_object_set_data(G_OBJECT(self->password_entry), "is-error-entry",
			  GINT_TO_POINTER(0));
	g_object_set_data(G_OBJECT(self->address_entry), "is-error-entry",
			  GINT_TO_POINTER(0));
	g_object_set_data(G_OBJECT(self->vcode_entry), "is-error-entry",
			  GINT_TO_POINTER(0));
	g_object_set_data(G_OBJECT(self->user_name_entry), "is-error-entry",
			  GINT_TO_POINTER(0));

	/* 默认处于登陆界面 */
	self->is_first_goto_register_page = true;
	self->is_registering		  = false;
	self->is_need_verification_code	  = false;
	//
	self->relate_return_button = NULL;
}
